#define _USE_MATH_DEFINES
#include <iostream>
#include <cmath>
#include "EquationSolver.h"

using namespace std;

class func1: public Function
{
    public:
        double get_value(double x){
            if (x == 0){
                cout << "Error: divided by zero!" << endl;
                return 0;
            }else if (cos(x) == 0){
                cout << "Error: 'tan(x)' does not exist!" <<endl;
                return 0;
            }else{
                return 1.0/x-tan(x);
            }
        }
}f1;

class func2: public Function
{
    public:
        double get_value(double x){
            if (x == 0){
                cout<<"Error: divided by zero!"<<endl;
                return 0;
            }else{
                return 1.0/x-pow(2,x);
            }
        }
}f2;

class func3: public Function
{
    public:
        double get_value(double x){
            return pow(2,-x)+exp(x)+2*cos(x)-6;
        }
}f3;

class func4: public Function
{
    public:
        double get_value(double x){
            double div = 2*x*x*x-9*x*x+18*x-2;
            if (div == 0){
                cout<<"Error: Divided by zero!"<<endl;
                return 0;
            }else{
                return 1.0*(x*x*x+4*x*x+3*x+5)/div;
            }
        }
}f4;

int main()
{
    cout << "Bisection Method Test: "<<endl;
    double e = 1e-8;
    double d = 1e-8;
    double m = 30;
    Bisection bis_solver(e,d,m);
    
    InitInput input1(f1),input2(f2),input3(f3),input4(f4);
    input1.setBisectionInput(e, M_PI_2);
    double x1 = bis_solver.solve(input1);
    cout << "the approximate root of f1: x1 = "<< x1 <<endl;
    cout << "the value of the root: f1(x1) = "<< f1.get_value(x1) <<endl;
    cout <<endl;

    input2.setBisectionInput(e, 1);
    double x2 = bis_solver.solve(input2);
    cout << "the approximate root of f2: x2 = "<< x2 <<endl;
    cout << "the value of the root: f2(x2) = "<< f2.get_value(x2) <<endl;
    cout <<endl;
    
    input3.setBisectionInput(1, 3);
    double x3 = bis_solver.solve(input3);
    cout << "the approximate root of f3: x3 = "<< x3 <<endl;
    cout << "the value of the root: f3(x3) = "<< f3.get_value(x3) <<endl;
    cout <<endl;

    input4.setBisectionInput(e, 4);
    double x4 = bis_solver.solve(input4);
    cout << "the approximate root of f4: x4 = "<< x4 <<endl;
    cout << "the value of the root: f4(x4) = "<< f4.get_value(x4) <<endl;

    return 0;
}